<html>

<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
</head>

<body>

    <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/css/bootstrap.min.css" rel="stylesheet"
        integrity="sha384-F3w7mX95PdgyTmZZMECAngseQB83DfGTowi0iMjiWaeVhAn4FJkqJByhZMI3AhiU" crossorigin="anonymous">
    <script src="https://cdn.jsdelivr.net/npm/bootstrap@5.1.1/dist/js/bootstrap.bundle.min.js"
        integrity="sha384-/bQdsTh/da6pkI1MST/rWKFNjaCP5gBSY4sEBT38Q/9RBh9AH40zEOg7Hlq2THRZ"
        crossorigin="anonymous"></script>

    <script src="https://unpkg.com/vue@next"></script>

    <main class="container">
        <div id="XmlEditorApp">

            <h1>以撒的结合Players.xml在线编辑器</h1>

            <input type="file" @change='open_file' id='file_selector' hidden>
            <a id="save_file_href" hidden>save me</a>

            <button class="btn btn-link" @click='open'>打开XML</button>
            <button class="btn btn-link" @click='save'>保存XML</button>
            <hr>
            <div class='alert alert-primary'>
                请将下载后的xml文件放到您的mod文件夹的此位置（来新增内容，不要指定角色id）：content\players.xml
                <hr>
                相对于忏悔游戏的完整路径为：The Binding of Isaac Rebirth\mods\<code>您的mod名称</code>\content\players.xml
                <hr>
                你可以打开游戏解包后的xml来参考。
            </div>
            <div class="card">
                <div class="card-body">
                    <label for='xml-root' class="form-label">根目录： </label>
                    <input id='xml-root' class="form-control" v-model="xmlprops.root" />

                    <label for='xml-portraitroot' class="form-label">外观图片跟目录： </label>
                    <input id='xml-portraitroot' class="form-control" v-model="xmlprops.portraitroot" />

                    <label for='xml-nameimageroot' class="form-label">名字图片根目录： </label>
                    <input id='xml-nameimageroot' class="form-control" v-model="xmlprops.nameimageroot" />

                    <label for='xml-bigportraitroot' class="form-label">外观（大）根目录： </label>
                    <input id='xml-bigportraitroot' class="form-control" v-model="xmlprops.bigportraitroot" />

                </div>
            </div>
            <div class="card">

                <div class="list-group">
                    <template v-for="(xml,i) in xmls">
                        <button :class='"list-group-item list-group-item-action"+(editing==i?" active":"")'
                            @click='editing=i'>
                            编辑角色{{i+1}}({{xml.name}})
                        </button>
                    </template>

                    <button class='list-group-item list-group-item-action list-group-item-success'
                        @click='new_xml'>增加新角色</button>
                </div>
                <div v-for="(xml,i) in xmls">
                    <span v-if='editing == i'>
                        <div class="card-body">
                            <h1>角色 {{ editing+1 }}
                                <button @click='remove_xml(i)' class="btn btn-sm btn-danger">删除此角色</button>
                            </h1>

                            <hr>

                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='id' name='角色id'
                            desc='一般不要指定这个id，除非你想覆盖游戏中的某些内容'></list-item-text>


                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='name' name='角色名'
                                desc='角色的名字，需要和CharacterMenu.anm2文件内容对应'></list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='skin' name='角色皮肤' desc='皮肤的纹理图片路径'>
                                <ensure-desc>{{xmlprops.root + xmls[editing].skin}}</ensure-desc>
                            </list-item-text>

                            <list-item-option :i='i' :xml='xmls[editing]' xmlname='skinColor' name='皮肤颜色'
                            desc='' :options='[["-1","全选"],["0","白色"],["1","黑色"],["2","蓝色"],["3","红色"],["4","绿色"],["5","灰色"]]'></list-item-option>

                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='nameimage' name='名字图片路径'
                                desc='VS.界面的名字图片'>
                                <ensure-desc>{{xmlprops.nameimageroot + xmls[editing].nameimage}}</ensure-desc>
                            </list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='portrait' name='外观图片路径'
                                desc='VS.界面的外观图片'>
                                <ensure-desc>{{xmlprops.portraitroot + xmls[editing].portrait}}</ensure-desc>
                            </list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='bigportrait' name='外观（大）图片路径'
                                desc='下层动画的外观图片'>
                                <ensure-desc>{{xmlprops.bigportraitroot + xmls[editing].bigportrait}}</ensure-desc>
                            </list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='hp' name='红心数量' desc='（1=半血）'>
                            </list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='armor' name='魂心数量' desc='（1=半血）'>
                            </list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='black' name='黑心数量' desc='（1=半血）'>
                            </list-item-text>

                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='costume' name='服饰' desc=''>
                            </list-item-text>

                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='costumeSuffix' name='服饰前缀' desc=''>
                            </list-item-text>


                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='items' name='初始道具'
                                desc='多个道具用逗号隔开，比如:1,14,16'></list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='bombs' name='初始炸弹' desc='初始炸弹数量'>
                            </list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='keys' name='初始钥匙' desc='初始钥匙数量'>
                            </list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='coins' name='初始金币' desc='初始金币数量'>
                            </list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='card' name='初始卡牌' desc='初始卡牌id'>
                            </list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='pill' name='初始药丸' desc='初始药丸id'>
                            </list-item-text>
                            <list-item-bool :i='i' :xml='xmls[editing]' xmlname='canShoot' name='可以射击' desc='初始是否可以射击（或蒙眼）'>
                            </list-item-bool>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='achievement' name='成就id'
                                desc='将角色绑定到一个成就id上'></list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='broken' name='碎心数量' desc='初始的碎心数量'>
                            </list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='pocketActive' name='口袋主动道具id'
                                desc='初始口袋道具的id'></list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='birthright' name='长子权'
                                desc='捡起长子权时的描述信息'></list-item-text>
                            <list-item-text :i='i' :xml='xmls[editing]' xmlname='bSkinParent' name='表皮肤'
                                desc='里角色对应的表角色名字'></list-item-text>

                            <list-item-bool :i='i' :xml='xmls[editing]' xmlname='hidden' name='隐藏'
                                desc='角色不会显示在角色列表中'></list-item-bool>


                            <div class="form-check form-switch">
                                <input class="form-check-input" type="checkbox" value="" :id='"xml-use-hair-"+i'
                                    v-model="xmls[editing]['use_'+'hair']">
                                <label class="form-check-label" :for='"xml-use-hair-"+i'>
                                    附加发型
                                </label>
                            </div>
                            <template v-if='xmls[editing].use_hair'>
                                <div>
                                    发型的图片（比如伊甸），每行写一个发型图片
                                </div>

                                <textarea class="form-control" v-model='xmls[editing].hairs'></textarea>
                                <div>
                                    <template v-for='hair of xmls[editing].hairs.split("\n")'>
                                        <template v-if='hair.length > 0'>
                                            <ensure-desc>{{xmlprops.root + hair}}</ensure-desc> <br>
                                        </template>
                                    </template>
                                </div>
                            </template>
                        </div>
                    </span>
                </div>

            </div>
        </div>

        <hr>
        <p>
            更多内容见<a class="btn btn-sm btn-link" href="http://frto027.gitee.io/isaac-editors/">Frto027的以撒Mod工具集合</a>

            <br>
            这里是Frto027，如果你想要获取此页上数据更多详细信息，请通过<a href="https://space.bilibili.com/11948678">B站</a>、<a
                href="https://github.com/frto027">Github</a>、<a href="https://gitee.com/frto027/">Gitee</a>、<a
                href="https://tieba.baidu.com/home/main?un=602706150">贴吧</a>等渠道联系我。
            <br>
    
            页面UI使用<a class="btn btn-link btn-sm" href="https://v3.vuejs.org/">vue</a>和<a class="btn btn-link btn-sm" href="https://getbootstrap.com/">bootstrap</a>潦草绘制
        </p>

    </main>


    <script>
        const BoolProps = ['canShoot', 'hidden']
        const PlayerEditor = {
            data() {
                return {
                    editing: -1,
                    xmls: [
                    ],
                    xmlprops: {
                        root: "gfx/characters/costumes/",
                        portraitroot: "gfx/ui/boss/",
                        nameimageroot: "gfx/ui/boss/",
                        bigportraitroot: "gfx/ui/stage/"
                    }

                }
            },
            methods: {
                new_xml() {
                    this.xmls.push(
                        {
                            use_name:true,
                            name: "Dear Isaac",
                            
                            use_skin:true,
                            skin: "Character_001_Isaac.png",
                            
                            use_hp:true,
                            hp: "6",
                            
                            use_bombs:true,
                            bombs: "1",
                            
                            use_nameimage:true,
                            nameimage: "PlayerName_01_Isaac.png",
                            
                            use_portrait:true,
                            portrait: "PlayerPortrait_01_Isaac.png",
                            
                            use_bigportrait:true,
                            bigportrait: "PlayerPortraitBig_01_Isaac.png",
                            
                            use_skinColor:true,
                            skinColor: "-1",
                            
                            use_birthright:true,
                            birthright: "not done",
                            
                            use_hair:false,
                            hairs: ""
                        }
                    )
                },
                remove_xml(i) {
                    if (confirm('要删除角色“' + this.xmls[i].name + '”吗？')) {
                        for (let j = i; j < this.xmls.length - 1; j++) {
                            this.xmls[j] = this.xmls[j + 1]
                        }
                        this.xmls.length = this.xmls.length - 1
                        this.editing = -1
                        alert("已删除")
                    }
                },
                open() {
                    document.getElementById('file_selector').click()
                },
                async open_file(e) {
                    let text = await (e.target.files[0].text());
                    let parser = new DOMParser()
                    let xml = parser.parseFromString(text, 'application/xml')

                    if (xml.children[0] == undefined || xml.children[0].tagName !== "players") {
                        alert("文件错误：不是player.xml或文件格式不正确")
                        return
                    }

                    let data = []
                    for (let child of xml.children[0].children) {
                        if (child.tagName != 'player') {
                            alert("文件错误：不是player.xml或文件格式不正确")
                            return
                        }
                        let data_item = {}
                        for (let attr of child.getAttributeNames()) {
                            //不要加载ID

                            data_item['use_' + attr] = true
                            let value = child.getAttribute(attr)

                            if (BoolProps.indexOf(attr) != -1) {
                                value = value == 'true'
                            }

                            data_item[attr] = value
                        }

                        //hairs
                        for (let player_child of child.children) {
                            if (player_child.tagName == 'hair') {
                                data_item.use_hair = 'true'
                                if (data_item.hairs == undefined) {
                                    data_item.hairs = ''
                                } else {
                                    data_item.hairs += '\n'
                                }
                                let hair_path = player_child.getAttribute('gfx')
                                data_item.hairs += hair_path
                            }
                        }
                        if (data_item.hairs == undefined) {
                            data_item.hairs = ''
                        }


                        data.push(data_item)
                    }
                    this.xmls = data
                    this.xmlprops.root = xml.children[0].getAttribute('root')
                    this.xmlprops.portraitroot = xml.children[0].getAttribute('portraitroot')
                    this.xmlprops.nameimageroot = xml.children[0].getAttribute('nameimageroot')
                    this.xmlprops.bigportraitroot = xml.children[0].getAttribute('bigportraitroot')
                },
                save() {
                    let xmlroot = document.implementation.createDocument('', '', null)
                    players = xmlroot.createElement('players')
                    for (let prop in this.xmlprops) {
                        players.setAttribute(prop, this.xmlprops[prop])
                    }
                    xmlroot.appendChild(players)

                    for (let player of this.xmls) {
                        let playerNode = xmlroot.createElement('player')
                        players.appendChild(playerNode)

                        for (let props in player) {
                            if (!(props.startsWith('use_'))) {
                                continue
                            }
                            if (player[props] == undefined || player[props] == false) {
                                continue
                            }
                            let props_actual = props.substr(4)
                            let props_value = player[props_actual]

                            if (props_actual == 'hair') {
                                for (let hair of player.hairs.split('\n')) {
                                    if (hair.length == 0)
                                        continue
                                    let hairNode = xmlroot.createElement('hair')
                                    hairNode.setAttribute('gfx', hair)
                                    playerNode.appendChild(hairNode)
                                }
                                continue
                            }

                            if (props_value == undefined) {
                                continue
                            }

                            if (BoolProps.indexOf(props_actual) != -1) {
                                props_value = props_value ? 'true' : 'false'
                            }

                            playerNode.setAttribute(props_actual, props_value)
                        }
                    }


                    let save_xml_text = new XMLSerializer().serializeToString(xmlroot)
                    var save_file_href = document.getElementById("save_file_href")
                    save_file_href.setAttribute('href', 'data:text/plain;charset=utf-8,' + encodeURIComponent(save_xml_text));
                    save_file_href.setAttribute('download', 'players.xml');
                    save_file_href.click()
                }
            }
        }



        let app = Vue.createApp(PlayerEditor)
        .component('ensure-desc', {
                template: `请确保resources/<slot></slot>存在`
            })
            .component('list-item-text', {
                props: ['xmlname', 'desc', 'name', 'listseq', 'xml', 'i'],
                template: `
                        <div class="form-check form-switch">
                        <input class="form-check-input" type="checkbox" value="" :id='"xml-use-"+name+"-"+i' v-model="xml['use_'+xmlname]">
                        <label class="form-check-label" :for='"xml-use-"+name+"-"+i'>
                            指定“{{name}}”
                        </label>
                        </div>
                        <template v-if="xml['use_'+xmlname]">
                            <label class="form-label" :for='"xml-"+name+"-"+i' >{{name}}： </label>
                            <input class="form-control" :id='"xml-"+name+"-"+i' v-model="xml[xmlname]" />
                            <div>{{desc}} <br> <slot></slot></div>
                        </template>

                        <hr>
                    `
            })
            .component('list-item-bool',{
                props: ['xmlname', 'desc', 'name', 'listseq', 'xml', 'i'],
                template:`
                    <div class="form-check form-switch">
                    <input class="form-check-input" type="checkbox" value="" :id='"xml-use-"+name+"-"+i' v-model="xml['use_'+xmlname]">
                    <label class="form-check-label" :for='"xml-use-"+name+"-"+i'>
                        指定“{{name}}”
                    </label>
                    </div>
                    <div class="form-check form-check-inline" v-if="xml['use_'+xmlname]">
                        <input type="checkbox" class="form-check-input" :id='"xml-"+name+"-"+i' v-model="xml[xmlname]" />
                        <label class="form-check-label" :for='"xml-"+name+"-"+i' >{{name}}</label>
                        <div>{{desc}} <br> <slot></slot></div>
                    </div>

                    <hr>
                `
            })
            .component('list-item-option',{
                props: ['xmlname', 'desc', 'name','options', 'listseq', 'xml', 'i'],
                template:`
                    <div class="form-check form-switch">
                    <input class="form-check-input" type="checkbox" value="" :id='"xml-use-"+name+"-"+i' v-model="xml['use_'+xmlname]">
                    <label class="form-check-label" :for='"xml-use-"+name+"-"+i'>
                        指定“{{name}}”
                    </label>
                    </div>
                    <template v-if="xml['use_'+xmlname]">

                        <label :for='"xml-"+name+"-"+i'>{{name}}： </label>

                        <select class="form-select" aria-label="Default select example" :id='"xml-"+name+"-"+i'
                        v-model="xml[xmlname]">

                            <option v-for="des of options" :value="des instanceof Array ? des[0] : des">{{des instanceof Array ? (des[1] || des[0]): des}}</option>
                        </select>
                        <div>{{desc}} <br> <slot></slot></div>

                    </template>

                    <hr>
                `
            })
            .component('list-item-multioption',{
                props: ['xmlname', 'desc', 'name','options', 'xml','propobj', 'i'],
                template:`
                    <div class="form-check form-switch">
                    <input class="form-check-input" type="checkbox" value="" :id='"xml-use-"+name+"-"+i' v-model="xml['use_'+xmlname]">
                    <label class="form-check-label" :for='"xml-use-"+name+"-"+i'>
                        指定“{{name}}”
                    </label>
                    </div>
                    <template v-if="xml['use_'+xmlname]">

                        <label>{{name}}： </label>

                            <div class="form-check form-check-inline" v-for="des of options">
                                <label class="form-check-label" :for='"xml-option-"+name+"-" + des + "-" +i'>{{des instanceof Array ? (des[1] || des[0]): des}}</label>
                                <input class="form-check-input" type="checkbox" value="" :id='"xml-option-"+name+"-" + des + "-" +i' v-model="xml[propobj][des instanceof Array ? des[0] : des]">

                            </div>
                        <div>{{desc}} <br> <slot></slot></div>

                    </template>

                    <hr>
                `
            })
            .mount('#XmlEditorApp')
    </script>

</body>

</html>